﻿#region Copyright & licence

// This file is part of Refix.
// 
// Refix is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
// 
// Refix is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License along with Refix.  If not, see <http://www.gnu.org/licenses/>.
// 
// Copyright (C) 2010-11 David Musgrove and others.

#endregion

using System;
using System.IO;

using Moq;

using NUnit.Framework;

using Refix.Core;
using Refix.Core.Repository;
using Refix.RepositoryBrowser.Models;
using Refix.RepositoryBrowser.Presenters;

namespace Refix.RepositoryBrowser.Tests.Presenters
{
    [TestFixture]
    public class BrowserPresenterTests
    {
        [Test]
        public void SetDirectory_SetsRepositoryModelFromFactoryOnModel()
        {
            var repositoryModel = new RepositoryItem();
            var mockModel = new Mock<IRepositoryModel>();
            var mockFactory = new Mock<IRepositoryModelFactory>();
            var presenter = new BrowserPresenter
            {
                Model = mockModel.Object,
                RepositoryModelFactory = mockFactory.Object
            };
            string directory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));

            mockModel.SetupSet(m => m.Repository = repositoryModel)
                .Verifiable("SetDirectory method should set new RepositoryItem on model.");
            mockFactory.Setup(f => f.SetDirectory(directory))
                .Verifiable("SetDirectory method should call SetDirectory on factory.");
            mockFactory.Setup(f => f.ConstructModel(mockModel.Object)).Returns(repositoryModel)
                .Verifiable("SetDirectory method should call ConstructModel on factory.");

            Directory.CreateDirectory(directory);
            presenter.SetDirectory(directory);
            Directory.Delete(directory);

            mockModel.VerifyAll();
            mockFactory.VerifyAll();
        }

        [Test]
        public void SetDirectory_ReportsAndThenClearsStatus()
        {
            var mockModel = new Mock<IRepositoryModel>();
            var mockFactory = new Mock<IRepositoryModelFactory>();
            var presenter = new BrowserPresenter
            {
                Model = mockModel.Object,
                RepositoryModelFactory = mockFactory.Object
            };
            string folder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));

            mockModel.Setup(m => m.ReportStatus(It.Is<string>(s => !s.IsNullOrEmpty())))
                .Verifiable("SetDirectory method should call ReportStatus to set status.");
            mockModel.Setup(m => m.ReportStatus(null))
                .Verifiable("SetDirectory method should call ReportStatus to clear status.");
            
            Directory.CreateDirectory(folder);
            presenter.SetDirectory(folder);
            Directory.Delete(folder);

            mockModel.VerifyAll();
            mockFactory.VerifyAll();
        }

        [Test]
        public void SelectRepositoryItem_SetsSelectedItemOnModel()
        {
            var item = new RepositoryItem();
            var mockModel = new Mock<IRepositoryModel>();
            var presenter = new BrowserPresenter
            {
                Model = mockModel.Object
            };

            mockModel.SetupSet(m => m.SelectedItem = item)
                .Verifiable("SelectRepository should set SelectedItem property on model.");

            presenter.SelectRepositoryItem(item);

            mockModel.VerifyAll();
        }

        [Test]
        public void SaveRepositoryItem_PutsParentComponentItemIntoRepository()
        {
            var componentItem = new RepositoryItem { Component = new Component() };
            var componentVersionItem = new RepositoryItem { Parent = componentItem };
            var mockModel = new Mock<IRepositoryModel>();
            var mockRepository = new Mock<ILocalRepository>();
            var presenter = new BrowserPresenter
            {
                Model = mockModel.Object,
                Repository = mockRepository.Object
            };

            mockRepository.Setup(r => r.PutComponent(It.Is<Component>(c => c == componentItem.Component)))
                .Verifiable("SaveRepositoryItem method should call PutComponent on repository.");

            presenter.SaveRepositoryItem(componentVersionItem);

            mockModel.VerifyAll();
        }

        [Test]
        public void SaveRepositoryItem_ResetsSelectedItemOnModel()
        {
            var componentItem = new RepositoryItem { Component = new Component() };
            var componentVersionItem = new RepositoryItem { Parent = componentItem };
            var mockModel = new Mock<IRepositoryModel>();
            var mockRepository = new Mock<ILocalRepository>();
            var presenter = new BrowserPresenter
            {
                Model = mockModel.Object,
                Repository = mockRepository.Object
            };

            mockModel.SetupSet(m => m.SelectedItem = componentVersionItem)
                .Verifiable("SaveRepositoryItem should set SelectedItem property on model.");

            presenter.SaveRepositoryItem(componentVersionItem);

            mockModel.VerifyAll();
        }

        [Test]
        public void AddFileToRepository_CopiesSourceFileToItemDirectory()
        {
            string sourceFileName = Path.GetTempFileName();
            string tempFolder = Directory.GetCurrentDirectory();
            string destinationFileName = Path.Combine(tempFolder, Path.GetFileName(sourceFileName));
            var item = new RepositoryItem {Directory = tempFolder};
            var mockModel = new Mock<IRepositoryModel>();

            var presenter = new BrowserPresenter
            {
                Model = mockModel.Object
            };

            Assert.False(File.Exists(destinationFileName),
                "DEVELOPER ERROR: Destination file should not exist before test starts.");
            presenter.AddFileToRepository(item, sourceFileName);
            Assert.True(File.Exists(destinationFileName),
                "AddFileToRepository method should create file in item directory.");

            File.Delete(sourceFileName);
            File.Delete(destinationFileName);
        }

        [Test]
        public void AddFileToRepository_ResetsSelectedItemOnModel()
        {
            string sourceFileName = Path.GetTempFileName();
            string tempFolder = Directory.GetCurrentDirectory();
            string destinationFileName = Path.Combine(tempFolder, Path.GetFileName(sourceFileName));
            var item = new RepositoryItem { Directory = tempFolder };
            var mockModel = new Mock<IRepositoryModel>();

            mockModel.SetupSet(m => m.SelectedItem = item)
                .Verifiable("AddFileToRepositroy method should set SelectedItem property on model.");

            var presenter = new BrowserPresenter
            {
                Model = mockModel.Object
            };

            presenter.AddFileToRepository(item, sourceFileName);

            mockModel.VerifyAll();

            File.Delete(sourceFileName);
            if (File.Exists(destinationFileName))
            {
                File.Delete(destinationFileName);
            }
        }

        [Test]
        public void RemoveFileFromRepository_DeletesFileFromItemDirectory()
        {
            string fullFileName = Path.GetTempFileName();
            string fileName = Path.GetFileName(fullFileName);
            string directoryName = Path.GetDirectoryName(fullFileName);
            var item = new RepositoryItem { Directory = directoryName };
            var mockModel = new Mock<IRepositoryModel>();

            var presenter = new BrowserPresenter
            {
                Model = mockModel.Object
            };

            Assert.True(File.Exists(fullFileName),
                "DEVELOPER ERROR: Temp file should exist before test starts.");
            presenter.RemoveFileFromRepository(item, fileName);
            Assert.False(File.Exists(fullFileName),
                "Temp file should be deleted by RemoveFileFromRepository method.");
        }

        [Test]
        public void RemoveFileFromRepository_ResetsSelectedItemOnModel()
        {
            string fullFileName = Path.GetTempFileName();
            string fileName = Path.GetFileName(fullFileName);
            string directoryName = Path.GetDirectoryName(fullFileName);
            var item = new RepositoryItem { Directory = directoryName };
            var mockModel = new Mock<IRepositoryModel>();

            mockModel.SetupSet(m => m.SelectedItem = item)
                .Verifiable("RemoveFileFromRepository method should set SelectedItem property on model.");

            var presenter = new BrowserPresenter
            {
                Model = mockModel.Object
            };

            presenter.RemoveFileFromRepository(item, fileName);

            mockModel.VerifyAll();
        }
    }
}